﻿using Microsoft.Extensions.Logging;
using JESAI.Polly.Results;
using Polly;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JESAI.Polly.Factorys
{
    /// <summary>
    /// Polly封装 
    /// </summary>

    public class PollyServicesFactory
    {
        private readonly ILogger Logger;
        public PollyServicesFactory(ILogger logger)
        {
            Logger = logger;
        }

        #region 重试 
        /// <summary>
        /// 组合使用Warp
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public ISyncPolicy RetryWarp<TException>(int num) where TException : Exception
        {
            var policy = Policy
             .Handle<TException>()
             .Retry(num, (ex, count) =>
             {
                 Logger.LogInformation($"[Polly]执行失败!重试次数 {count}\r\n异常信息：{ex.Message}异常来自 {ex.GetType().Name}");
             });
            return policy;
        }
        public IAsyncPolicy RetryWarpAsync<TException>(int num) where TException : Exception
        {
            var policy = Policy
             .Handle<TException>()
             .RetryAsync(num, (ex, count) =>
             {
                 Logger.LogInformation($"[Polly]执行失败!重试次数 {count}\r\n异常信息：{ex.Message}异常来自 {ex.GetType().Name}");
             });
            return policy;
        }
        /// <summary>
        /// 服务重试 及重试次数
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="num"></param>
        public void PollyRetry<TException>(Action action, int num) where TException : Exception
        {
            var policy = Policy
              .Handle<TException>()
              .Retry(num, (ex, count) =>
              {
                  Logger.LogInformation($"[Polly]{action.Method.Name}执行失败!重试次数 {count}\r\n异常信息：{ex.Message}异常来自 {ex.GetType().Name}");
              });

            policy.Execute(action);
        }

        public TResult PollyResultRetry<TException, TResult>(Func<TResult> action, int num) where TException : Exception
        {
            var policy = Policy
              .Handle<TException>()
              .Retry(num, (ex, count) =>
              {
                  Logger.LogInformation($"[Polly]{action.Method.Name}执行失败!重试次数 {count}\r\n异常信息：{ex.Message}异常来自 {ex.GetType().Name}");
              });

            return policy.Execute(action);
        }

        /// <summary>
        /// 服务重试 及重试次数
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="num"></param>
        public async Task PollyRetryAsync<TException>(Func<Task> action, int num) where TException : Exception
        {
            var policy = Policy
              .Handle<TException>()
              .RetryAsync(num, (ex, count) =>
              {
                  Logger.LogInformation($"[Polly]{action.Method.Name}执行失败!重试次数 {count}\r\n异常信息：{ex.Message}异常来自 {ex.GetType().Name}");
              });

            await policy.ExecuteAsync(action);
        }

        public async Task<TResult> PollyResultRetryAsync<TException, TResult>(Func<Task<TResult>> action, int num) where TException : Exception
        {
            var policy = Policy
              .Handle<TException>()
              .RetryAsync(num, (ex, count) =>
              {
                  Logger.LogInformation($"[Polly]{action.Method.Name}执行失败!重试次数 {count}\r\n异常信息：{ex.Message}异常来自 {ex.GetType().Name}");
              });

            return await policy.ExecuteAsync(action);
        }

        #endregion

        #region 重试 TimeSpan
        /// <summary>
        /// 重试 Warp 
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="timeSpans"></param>
        /// <returns></returns>
        public ISyncPolicy WaitAndRetryWarp<TException>(params TimeSpan[] timeSpans) where TException : Exception
        {
            var policy = Policy
            .Handle<TException>()
            .WaitAndRetry(timeSpans, (e, tiempo, intento, contexto) =>
            {
                Logger.LogInformation($"[Polly]异常信息：{e.Message}异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");
            });
            return policy;
        }

        public IAsyncPolicy WaitAndRetryWarpAsync<TException>(params TimeSpan[] timeSpans) where TException : Exception
        {
            var policy = Policy
            .Handle<TException>()
            .WaitAndRetryAsync(timeSpans, (e, tiempo, intento, contexto) =>
            {
                Logger.LogInformation($"[Polly]异常信息：{e.Message}异常: {intento:00} (调用秒数:{tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");
            });
            return policy;
        }

        /// <summary>
        /// 按需要的周期重试
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="timeSpans"></param>
        /// <returns></returns>
        public void PollyWaitAndRetry<TException>(Action action, params TimeSpan[] timeSpans) where TException : Exception
        {
            var policy = Policy
            .Handle<TException>()
            .WaitAndRetry(timeSpans, (e, tiempo, intento, contexto) =>
            {
                Logger.LogInformation($"[Polly]{action.Method.Name}异常信息：{e.Message}异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");
            });
            policy.Execute(action);
        }


        public TResult PollyResultWaitAndRetry<TException, TResult>(Func<TResult> action, params TimeSpan[] timeSpans) where TException : Exception
        {
            var policy = Policy
            .Handle<TException>()
            .WaitAndRetry(timeSpans, (e, tiempo, intento, contexto) =>
            {
                Logger.LogInformation($"[Polly]{action.Method.Name}异常信息：{e.Message}异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");
            });
            return policy.Execute(action);
        }

        /// <summary>
        /// 按需要的周期重试
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="timeSpans"></param>
        /// <returns></returns>
        public async Task PollyWaitAndRetryAsync<TException>(Func<Task> action, params TimeSpan[] timeSpans) where TException : Exception
        {
            var policy = Policy
            .Handle<TException>()
            .WaitAndRetryAsync(timeSpans, (e, tiempo, intento, contexto) =>
            {

                Logger.LogInformation($"[Polly]{action.Method.Name}异常信息：{e.Message}异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");

            });
            await policy.ExecuteAsync(action);
        }

        public async Task<TResult> PollyResultWaitAndRetryAsync<TException, TResult>(Func<Task<TResult>> action, params TimeSpan[] timeSpans) where TException : Exception
        {
            var policy = Policy
            .Handle<TException>()
            .WaitAndRetryAsync(timeSpans, (e, tiempo, intento, contexto) =>
            {
                Logger.LogInformation($"[Polly]{action.Method.Name}异常信息：{e.Message}异常:{e.Message} {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");
            });
            return await policy.ExecuteAsync(action);
        }


        #endregion

        #region 指定特定返回值
        public ISyncPolicy<OperatorResult> FallBackWarp<TException>() where TException : Exception
        {
            var pollyfallback = Policy<OperatorResult>.Handle<TException>()
                  .Fallback(new OperatorResult
                  {
                      Result = ResultType.Fail,
                      Message = "执行失败"
                  });

            return pollyfallback;

        }


        public IAsyncPolicy<OperatorResult> FallBackWarpAsync<TException>() where TException : Exception
        {
            var pollyfallback = Policy<OperatorResult>.Handle<TException>()
                  .FallbackAsync(new OperatorResult
                  {
                      Result = ResultType.Fail,
                      Message = "执行失败"
                  });

            return pollyfallback;

        }
        /// <summary>
        /// 监控特定错误指定返回值
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public OperatorResult PollyFallBack<TException>(Func<OperatorResult> action) where TException : Exception
        {
            var pollyfallback = Policy<OperatorResult>.Handle<TException>()
                  .Fallback(() =>
                  {

                      return new OperatorResult
                      {
                          Result = ResultType.Fail,
                          Message = action.Method.Name + "执行失败"
                      };
                  });

            return pollyfallback.Execute(action);

        }

        /// <summary>
        /// 监控特定错误指定返回值
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public async Task<OperatorResult> PollyFallBackAsync<TException>(Func<Task<OperatorResult>> action) where TException : Exception
        {
            var pollyfallback = Policy<OperatorResult>.Handle<TException>()
                  .FallbackAsync(new OperatorResult
                  {
                      Result = ResultType.Fail,
                      Message = action.Method.Name + "执行失败"
                  }
                  );


            return await pollyfallback.ExecuteAsync(action);

        }
        #endregion


        #region 熔断

        public ISyncPolicy CircuitBreakerWarp<TException>(int num, TimeSpan timeSpan) where TException : Exception
        {
            var policy = Policy
          .Handle<TException>()
          .CircuitBreaker(num, timeSpan);
            return policy;
        }

        public IAsyncPolicy CircuitBreakerWarpAsync<TException>(int num, TimeSpan timeSpan) where TException : Exception
        {
            var policy = Policy
           .Handle<TException>()
           .CircuitBreakerAsync(num, timeSpan);
            return policy;
        }
        /// <summary>
        /// 熔断 仓壁隔离
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="num"></param>
        /// <param name="timeSpan"></param>
        public void PollyCircuitBreaker<TException>(Action action, int num, TimeSpan timeSpan) where TException : Exception
        {
            var policy = Policy
                   .Handle<TException>()
                   .CircuitBreaker(num, timeSpan);
            while (true)
            {
                try
                {
                    policy.Execute(action);
                }
                catch (Exception ex)
                {
                    Logger.LogInformation($"[Polly]{action.Method.Name}异常: {ex.Message} \t执行时间: {DateTime.Now}");
                }
                Thread.Sleep(100);
            }


        }
        public Task<TResult> PollyResultCircuitBreaker<TException, TResult>(Func<Task<TResult>> action, int num, TimeSpan timeSpan) where TException : Exception
        {
            var policy = Policy
                   .Handle<TException>()
                   .CircuitBreaker(num, timeSpan);
            while (true)
            {
                try
                {
                    return policy.Execute(action);
                }
                catch (Exception ex)
                {
                    Logger.LogInformation($"[Polly]{action.Method.Name}异常: {ex.Message} \t执行时间: {DateTime.Now}");
                }
                Thread.Sleep(100);
            }

        }
        /// <summary>
        /// 熔断 仓壁隔离
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="action"></param>
        /// <param name="num"></param>
        /// <param name="timeSpan"></param>
        public async Task PollyCircuitBreakerAsync<TException>(Func<Task> action, int num, TimeSpan timeSpan) where TException : Exception
        {
            var policy = Policy
             .Handle<TException>()
             .CircuitBreakerAsync(num, timeSpan);


            while (true)
            {
                try
                {
                    await policy.ExecuteAsync(action);
                }
                catch (Exception ex)
                {
                    Logger.LogInformation($"[Polly]{action.Method.Name}异常: {ex.Message} \t执行时间: {DateTime.Now}");
                }
                Thread.Sleep(100);
            }
        }

        public async Task<TResult> PollyResultCircuitBreakerAsync<TException, TResult>(Func<Task<TResult>> action, int num, TimeSpan timeSpan) where TException : Exception
        {
            var policy = Policy
              .Handle<TException>()
              .CircuitBreakerAsync(num, timeSpan);


            while (true)
            {
                try
                {
                    return await policy.ExecuteAsync(action);
                }
                catch (Exception ex)
                {
                    Logger.LogInformation($"[Polly]{action.Method.Name}异常: {ex.Message} \t执行时间: {DateTime.Now}");
                }
                Thread.Sleep(100);
            }
        }

        #endregion



        #region 组合各种场景
        public void PollyWarp(Action action, params ISyncPolicy[] syncPolicies)
        {
            var mixedPolicy = Policy.Wrap(syncPolicies);

            mixedPolicy.Execute(action);
        }
        public async Task PollyWarpAsync(Func<Task> action, params IAsyncPolicy[] syncPolicies)
        {
            var mixedPolicy = Policy.WrapAsync(syncPolicies);
            await mixedPolicy.ExecuteAsync(action);
        }
        #endregion
    }
}
